import { Service } from 'egg';
import { Transaction, col, fn } from 'sequelize';
import { v4 as uuidv4 } from 'uuid';
import * as fs from 'fs';
import * as dayjs from 'dayjs';

import { calculateDurningTime, generateAnswerData, answerExcelHeader } from './core/answer-excel';
import { TOTAL_QUESTION } from '../../constants/answer-progress-state';
import {
  SYMPTOM_START
} from '../../constants/feedback';
import { File } from '../util';
import {
  convertedScore,
  classficationConvertedScore
} from '../util/score';
import {
  createFileDescriptionList,
  createFileImage,
} from './core';
import Xlsx from '../util/xlsx';
import FileUtil from '../util/file';
import { getImageFileName } from '../util/image';
import GroupScore from './core/group-score';
import Email from '../util/email';

interface SaveAnswerParams {
  questionnaireUuid: string,
  mergeUuid?: string,
  name?: string,
  num?: string,
  tel: string,
  gender: number,
  maritalStatus: number,
  childrenSituation: number,
  age: number,
  education: number,
  score: number[],
  jobPosition?: string,
  affiliated?: string,
  workUnit?: string,
  operatingPost?: string,
  email: string
}

class AnswerService extends Service {
  /**
   * 获取已经回答过的问题答案
   * @param questionnaireId 问卷ID
   * @param userId 用户ID
   * @param t 事务
   * @return Promise<scoreList[]> 答案数组
   */
  async score(
    questionnaireId: number,
    userId: number,
    t: Transaction
  ) {
    const { ctx } = this;

    const merge = await ctx.model.MergeUserQuestionnaire.findOne({
      where: {
        FKUser: userId,
        FKQuestionnaire: questionnaireId
      }
    }, { transaction: t });

    if (!merge) {
      return false;
    }

    // 获取已经回答过的题目答案
    const answer = await ctx.model.Answer.findAll({
      where: {
        FKMergeUserQuestionnaire: merge.id,
      },
      attributes: [
        ['fk_question', 'questionId'],
        'score'
      ],
      order: [['fk_question', 'ASC']]
    }, { transaction: t });

    for (let i = answer?.length ?? 0; i < TOTAL_QUESTION; i += 1) {
      answer.push({
        questionId: i + 1,
        score: undefined
      });
    }

    return {
      scoreList: answer
    };
  }

  /**
   * 回答问题
   * @param questionnaireUuid 问卷uuid
   * @param userUuid 用户uuid
   * @param questionUuid 问题uuid
   * @param score 回答分数
   * @return {score: number} 回答的分数
   */
  async saveQuestionScore(
    questionnaireUuid: string,
    userUuid: string,
    questionUuid: string,
    score: number
  ) {
    const result = await this.ctx.model.transaction(async (t) => {
      const { ctx } = this;
      const [existUser, existQuestionnaire, existQuestion] = await Promise.all([
        await ctx.model.User.findOne({
          where: {
            uuid: userUuid
          }
        }, { transaction: t }),
        await ctx.model.Questionnaire.findOne({
          where: {
            uuid: questionnaireUuid
          }
        }, { transaction: t }),
        await ctx.model.Question.findOne({
          where: {
            uuid: questionUuid
          }
        }, { transaction: t })
      ]);

      if (!(existUser && existQuestion && existQuestionnaire)) {
        return false;
      }

      const merge = await ctx.model.MergeUserQuestionnaire.findOne({
        where: {
          FKUser: existUser.id,
          FKQuestionnaire: existQuestionnaire.id
        }
      }, { transaction: t });

      if (!merge) {
        return false;
      }

      // 没有则创建
      const [answer, created] = await ctx.model.Answer.findOrCreate({
        where: {
          FKMergeUserQuestionnaire: merge.id,
          FKQuestion: existQuestion.id,
        },
        defaults: {
          uuid: uuidv4(),
          score
        },
        transaction: t
      });

      if (!created) {
        // 已经存在，则更新成绩
        await ctx.model.Answer.update({
          score
        }, {
          where: {
            id: answer.id,
          },
          transaction: t
        });
      }

      // 是否答完卷
      if (existQuestion.id === TOTAL_QUESTION) {
        await ctx.model.MergeUserQuestionnaire.update({
          endTime: Number(new Date()),
          complateFlag: 1
        }, {
          where: {
            FKUser: existUser.id,
            FKQuestionnaire: existQuestionnaire.id
          },
          transaction: t
        });
      }
      return { score };
    });

    return result;
  }

  /**
   * 获取mergeUuid对应的userUuid和questionnaireUuid
   * @param mergeUuid merge uuid
   * @return {questionnaireUuid, userUuid} userUuid和questionnaireUuid
   */
  private async searchMergeByMergeUuid(mergeUuid: string) {
    const { ctx } = this;
    const merge = await ctx.model.MergeUserQuestionnaire.findOne({
      where: {
        uuid: mergeUuid
      }
    });

    if (!merge) {
      throw new Error('没有此反馈信息');
    }

    const { FKUser, FKQuestionnaire, email } = merge;
    const [existUser, existQuestionnaire] = await Promise.all([
      await ctx.model.User.findOne({
        where: {
          id: FKUser
        }
      }),
      await ctx.model.Questionnaire.findOne({
        where: {
          id: FKQuestionnaire
        }
      })]);

    if (!existUser && !existQuestionnaire) {
      throw new Error('没有此反馈信息');
    }

    return {
      questionnaireUuid: existQuestionnaire.uuid,
      userUuid: existUser.uuid,
      email
    };
  }

  /**
   * 获取mergeUuid对应的userUuid和questionnaireUuid
   * @param userUuid userUuid
   * @param questionnaireUuid questionnaireUuid
   * @return {string} mergeUuid
   */
  private async searchMergeByUserUuidAndQuestionnaireUuid(
    userUuid: string,
    questionnaireUuid: string
  ) {
    const { ctx } = this;

    const merge = await ctx.model.MergeUserQuestionnaire.findOne({
      attributes: ['uuid'],
      include: [
        {
          model: ctx.model.User,
          attributes: [],
          where: {
            uuid: userUuid
          },
          required: true
        },
        {
          model: ctx.model.Questionnaire,
          attributes: [],
          where: {
            uuid: questionnaireUuid
          },
        }
      ]
    });

    if (!merge) {
      throw new Error('没有回答');
    }

    return merge.uuid;
  }

  /**
   * 查询问卷总成绩对应的评语
   * 查询用户回答的问题答案
   * @param mergeId FKMergeUserQuestionnaire
   * @return { answers: [{score: number}] } 问卷总评语
   */
  private async getUserAnswer(mergeId: number, t: Transaction) {
    const { ctx } = this;
    const currentAnswerList = await ctx.model.Answer.findAll({
      where: {
        FKMergeUserQuestionnaire: mergeId,
      },
      attributes: [
        ['fk_question', 'questionId'],
        'score'
      ],
      raw: true
    }, { transaction: t });

    if (currentAnswerList.length !== TOTAL_QUESTION) {
      throw new Error('用户答题数量错误！无法生成反馈问卷');
    }

    return currentAnswerList;
  }

  private async getUserListAnswer(
    where, t: Transaction
  ) {
    const { ctx } = this;

    const groupAnswerListByMerge = await ctx
      .model
      .MergeUserQuestionnaire
      .findAll({
        include: [{
          model: ctx.model.Answer,
          attributes: [
            ['fk_question', 'questionId'],
            'score'
          ],
        }, {
          model: ctx.model.Questionnaire,
          attributes: [],
          include: [{
            model: ctx.model.Template,
            attributes: [],
          }]
        }],
        where: {
          complateFlag: 1,
          ...where
        },
      }, { transaction: t });

    return groupAnswerListByMerge;
  }

  /**
   * 获取一级分类下的二级分类数组
   * @param t 事务
   * @return {classficationList: []} 分类数组
   */
  private async classfication(t: Transaction) {
    const { ctx } = this;
    const classficationList = await ctx.model.Classification.findAll({
      include: [
        {
          model: ctx.model.Conclusion,
          attributes: ['id']
        }
      ],
      attributes: [
        ['id', 'classficationId'],
        ['name', 'classficationName']
      ],
      order: [['id', 'ASC']]
    }, { transaction: t });
    return classficationList;
  }

  /**
   * 计算每类conclusion的回答得分
   */
  async groupConclusionScore(mergeId: number, t: Transaction) {
    const { ctx } = this;
    const allConclusionsQuestionAnswer = await ctx.model.Conclusion.findAll({
      include: [
        {
          model: ctx.model.Question,
          through: { attributes: [] },
          attributes: ['id'],
          required: true,
          include: [
            {
              model: ctx.model.Answer,
              attributes: ['fk_question', 'score'],
              where: {
                FKMergeUserQuestionnaire: mergeId,
              },
            }
          ]
        }
      ],
      attributes: [
        ['id', 'conclusionId'],
        ['name', 'conclusionName']
      ],
      order: [['id', 'ASC']]
    }, { transaction: t });
    if (!allConclusionsQuestionAnswer) {
      throw new Error('每类成绩计算失败！');
    }
    // 处理allConclusionsQuestionAnswer为指定类型
    const conclusionAnswerList = allConclusionsQuestionAnswer.map((item) => {
      const { conclusionId, conclusionName, Questions: questionList } = item.dataValues;
      const answerList = questionList.map((questionItem) => {
        const { fk_question: questionId, score } = questionItem.Answers[0];
        return {
          questionId,
          score
        };
      });
      return {
        conclusionId,
        conclusionName,
        answerList
      };
    });

    return conclusionAnswerList;
  }

  /**
   * 统计文件答案
   * @param {mergeUuid, fileType} mergeUuid, 生成文件类型
   */
  public async createStatisticFile({
    mergeUuid,
    fileType,
    isView
  }: {
    mergeUuid: string,
    fileType: string,
    isView?: boolean
  }) {
    try {
      const result = await this.ctx.model.transaction(async (t) => {
        const { ctx } = this;

        const merge = await ctx.model.MergeUserQuestionnaire.findOne({
          where: {
            uuid: mergeUuid,
          },
          attributes: [
            ['id', 'mergeId'],
            ['fk_user', 'fkUser'],
            ['fk_questionnaire', 'fkQuestionnaire'],
          ],
          raw: true,
        }, { transaction: t });

        if (!merge) {
          throw new Error('没有此用户');
        }

        const { fkUser, fkQuestionnaire, mergeId } = merge;

        const [user, template] = await Promise.all([
          ctx.model.User.findOne({
            where: { id: fkUser },
            attributes: ['uuid'],
          }, { transaction: t }),
          ctx.model.Template.findOne({
            include: [
              {
                model: this.ctx.model.Questionnaire,
                where: { id: fkQuestionnaire },
                required: true
              },
            ],
            raw: true
          }, { transaction: t }),
        ]);

        if (!(user && template)) {
          throw new Error('没有此用户');
        }

        const [
          allColusionFeedback,
          currentAnswerList,
          classficationList,
        ] = await Promise.all([
          await ctx.service.feedback.searchAllColusionFeedback(t),
          await this.getUserAnswer(mergeId, t),
          await this.classfication(t)
        ]);

        if (!(allColusionFeedback
          && currentAnswerList
          && classficationList
        )) {
          throw new Error('问卷错误');
        }

        const groupScore = new GroupScore(currentAnswerList, allColusionFeedback);
        const conclusionScoreDesResult = groupScore.currentAnswerList;

        /** 折合百分比之后的分数 */
        const convertedConclusionScoreList = convertedScore(
          conclusionScoreDesResult,
          allColusionFeedback
        );

        /** echarts 数据 */
        const echartsData = classficationConvertedScore(
          classficationList,
          convertedConclusionScoreList
        );

        /** 创建文件中的文字数据 */
        const { epilog, title } = template;
        const { totalScore, description } = groupScore;
        const desctiptionList = createFileDescriptionList(conclusionScoreDesResult);

        /** 创建文件中的图片 */
        const imagePath = createFileImage(echartsData, totalScore, mergeUuid);

        const filePath = await File.saveQuestionnaireResultFile({
          mergeUuid,
          fileType,
          epilog,
          title,
          description,
          ...desctiptionList,
          ...imagePath,
          isView
        });

        return filePath;
      });

      return result;
    } catch (error) {
      console.error(error);
      return '';
    }
  }

  /**
   * 获取反馈信息
   */

  public async createStatisticData(mergeUuid: string) {
    try {
      const result = await this.ctx.model.transaction(async (t) => {
        const { ctx } = this;

        const merge = await ctx.model.MergeUserQuestionnaire.findOne({
          where: {
            uuid: mergeUuid,
          },
          attributes: [
            ['id', 'mergeId'],
            ['fk_user', 'fkUser'],
            ['fk_questionnaire', 'fkQuestionnaire'],
          ],
          raw: true,
        }, { transaction: t });

        if (!merge) {
          throw new Error('没有此用户');
        }

        const { fkUser, fkQuestionnaire, mergeId } = merge;

        const [user, template] = await Promise.all([
          ctx.model.User.findOne({
            where: { id: fkUser },
            attributes: ['uuid'],
          }, { transaction: t }),
          ctx.model.Template.findOne({
            include: [
              {
                model: this.ctx.model.Questionnaire,
                where: { id: fkQuestionnaire },
                required: true
              },
            ],
            raw: true
          }, { transaction: t }),
        ]);

        if (!(user && template)) {
          throw new Error('没有此用户');
        }

        const [
          allColusionFeedback,
          currentAnswerList,
          classficationList,
        ] = await Promise.all([
          await ctx.service.feedback.searchAllColusionFeedback(t),
          await this.getUserAnswer(mergeId, t),
          await this.classfication(t)
        ]);

        if (!(allColusionFeedback
          && currentAnswerList
          && classficationList
        )) {
          throw new Error('问卷错误');
        }

        const groupScore = new GroupScore(currentAnswerList, allColusionFeedback);
        const conclusionScoreDesResult = groupScore.currentAnswerList;

        /** 折合百分比之后的分数 */
        const convertedConclusionScoreList = convertedScore(
          conclusionScoreDesResult,
          allColusionFeedback
        );

        /** echarts 数据 */
        const echartsData = classficationConvertedScore(
          classficationList,
          convertedConclusionScoreList
        );

        /** 创建文字数据 */
        const { title, epilog } = template;
        const { totalScore, description } = groupScore;
        const descriptionList = createFileDescriptionList(conclusionScoreDesResult);

        /** 创建图片 */
        const {
          concludedImagePath,
          physicalImagePath,
          mentalImagePath,
          stressImagePath,
          solutionImagePath
        } = createFileImage(echartsData, totalScore, mergeUuid);

        return {
          title,
          description,
          ...descriptionList,
          epilog,
          concludedImage: getImageFileName(concludedImagePath),
          physicalImage: getImageFileName(physicalImagePath),
          mentalImage: getImageFileName(mentalImagePath),
          stressImage: getImageFileName(stressImagePath),
          solutionImage: getImageFileName(solutionImagePath)
        };
      });

      return result;
    } catch (error) {
      console.error(error);
      return '';
    }
  }

  private async sendEmail({
    mergeUuid,
    email
  }: {
    questionnaireUuid: string,
    userUuid: string,
    mergeUuid: string,
    email: string
  }) {
    // get docx and pdf file path
    const docxPath = await this.createStatisticFile({
      mergeUuid,
      fileType: 'docx'
    });

    // get docx and pdf buffer
    let docxBuffer: Buffer | null = fs.readFileSync(docxPath);

    // send mail with defined transport object
    const info = await Email.sendEmail(email, docxBuffer);

    // eslint-disable-next-line no-console
    console.log('Message sent: %s', info.messageId);

    docxBuffer = null;
  }

  /**
   * 发送 email
   */
  public async sendEmailByQuestionnaireUuidAndUserUuid(
    questionnaireUuid: string,
    userUuid: string,
    email: string
  ) {
    const mergeResult = await this
      .searchMergeByUserUuidAndQuestionnaireUuid(
        userUuid,
        questionnaireUuid
      );

    await this.sendEmail({
      questionnaireUuid,
      userUuid,
      mergeUuid: mergeResult,
      email
    });
  }

  /**
   * 根据mergeUuid发送email
   * @param mergeUuid merge uuid
   */
  public async sendEmailByMergeUuid(
    mergeUuid: string,
  ) {
    const mergeResult = await this.searchMergeByMergeUuid(mergeUuid);
    if (!mergeResult) {
      throw new Error('没有反馈记录！');
    }
    const { questionnaireUuid, userUuid, email } = mergeResult;

    if (!email) {
      return false;
    }

    // 注意这里的发送邮件是异步的！
    this.sendEmail({
      questionnaireUuid,
      userUuid,
      mergeUuid,
      email
    });

    return true;
  }

  public async searchList(
    templateUuid: string,
    questionnaireUuid: string,
    page: number,
    pageSize: number
  ) {
    const { ctx } = this;
    const whereQuestionnaireUuid = '$Questionnaire.uuid$';
    const whereTemplateUuid = '$Questionnaire->Template.uuid$';

    let where;

    if (
      templateUuid === 'all'
      && questionnaireUuid === 'all'
    ) {
      // 全选
      where = null;
    }

    if (
      templateUuid !== 'all'
      && questionnaireUuid === 'all'
    ) {
      // 一个模版下全选
      where = {
        [whereTemplateUuid]: templateUuid
      };
    }

    if (templateUuid !== 'all'
      && questionnaireUuid !== 'all') {
      where = {
        [whereTemplateUuid]: templateUuid,
        [whereQuestionnaireUuid]: questionnaireUuid
      };
    }

    const result = ctx.model.transaction(async (t) => {
      const [mergeUserQuestionnaireListOriginal, total] = await Promise.all([
        ctx.model.MergeUserQuestionnaire.findAll({
          include: [
            {
              model: ctx.model.User,
              attributes: []
            },
            {
              model: ctx.model.Answer,
              attributes: [],
            },
            {
              model: ctx.model.Questionnaire,
              attributes: [],
              include: [{
                model: ctx.model.Template,
                attributes: [],
              }]
            }
          ],
          attributes: [
            [col('MergeUserQuestionnaire.id'), 'id'],
            [fn('sum', col('Answers.score')), 'totalScore'],
            ['uuid', 'mergeUuid'],
            [col('User.tel'), 'tel'],
            'startTime',
            'email',
            'endTime',
            'complateFlag',
            [col('Questionnaire.uuid'), 'questionnaireUuid'],
            [col('Questionnaire.name'), 'questionnaireName'],
            [col('Questionnaire.Template.uuid'), 'templateUuid'],
            [col('Questionnaire.Template.title'), 'templateTitle']
          ],
          offset: (page - 1) * pageSize,
          limit: pageSize,
          subQuery: false,
          group: 'MergeUserQuestionnaire.id',
          raw: true,
          where: {
            ...where,
            // complateFlag: 1
          }
        }, { transaction: t }),
        ctx
          .model
          .MergeUserQuestionnaire
          .count({
            include: [
              {
                model: ctx.model.Questionnaire,
                attributes: [],
                include: [{
                  model: ctx.model.Template,
                  attributes: [],
                }]
              }
            ],
            where: {
              ...where,
              // complateFlag: 1
            }
          }, { transaction: t })
      ]);

      const mergeUserQuestionnaireList = mergeUserQuestionnaireListOriginal
        .map(
          (mergeUserQuestionnaire) => {
            const {
              mergeUuid,
              tel,
              totalScore,
              startTime,
              endTime,
              complateFlag,
              questionnaireUuid: userQuestionnaireUuid,
              templateUuid: userTemplateUuid,
              questionnaireName,
              templateTitle,
              email
            } = mergeUserQuestionnaire;
            let isInStandard: boolean | undefined;
            let durningTime: string | undefined;
            let afterComplateJudgeEndTime: string | undefined;

            if (complateFlag === 1 && startTime && endTime) {
              durningTime = calculateDurningTime(startTime, endTime);
              afterComplateJudgeEndTime = dayjs(endTime).format('YYYY[年]-MM[月]-DD[日] HH:mm:ss');
            }

            if (complateFlag === 1) {
              isInStandard = (totalScore ?? 0) > SYMPTOM_START;
            }

            return {
              mergeUuid,
              tel,
              isInStandard,
              durningTime,
              complateFlag,
              endTime: afterComplateJudgeEndTime,
              templateUuid: userTemplateUuid,
              questionnaireUuid: userQuestionnaireUuid,
              questionnaireName,
              templateTitle,
              email
            };
          }
        );

      return { total, mergeUserQuestionnaireList };
    });

    return result;
  }

  async downloadExcel(
    templateUuid: string,
    questionnaireUuid: string
  ) {
    const whereQuestionnaireUuid = '$Questionnaire.uuid$';
    const whereTemplateUuid = '$Questionnaire->Template.uuid$';

    let where;

    if (
      templateUuid === 'all'
      && questionnaireUuid === 'all'
    ) {
      // 全选
      where = null;
    }

    if (
      templateUuid !== 'all'
      && questionnaireUuid === 'all'
    ) {
      // 一个模版下全选
      where = {
        [whereTemplateUuid]: templateUuid
      };
    }

    if (templateUuid !== 'all'
      && questionnaireUuid !== 'all') {
      where = {
        [whereTemplateUuid]: templateUuid,
        [whereQuestionnaireUuid]: questionnaireUuid
      };
    }

    const { ctx } = this;

    const realResolvePath = ctx.model.transaction(async (t) => {
      const mergeList = await ctx
        .model
        .MergeUserQuestionnaire
        .findAll({
          attributes: [
            'startTime',
            'endTime',
            'email',
            'uuid'
          ],
          include: [{
            model: ctx.model.Questionnaire,
            attributes: [],
            include: [{
              model: ctx.model.Template,
              attributes: []
            }]
          }, {
            model: ctx.model.Answer,
            attributes: []
          }, {
            model: ctx.model.User,
            attributes: [
              'tel',
              'name',
              'num',
              'gender',
              'genderName',
              'maritalStatus',
              'maritalStatusName',
              'childrenSituation',
              'childrenSituationName',
              'age',
              'ageName',
              'education',
              'educationName',
              'workUnit',
              'affiliated',
              'jobPosition',
              'operatingPost'
            ]
          }],
          where
        }, { transaction: t });
      const userListAnswer = await this.getUserListAnswer(where, t);

      const answerData = generateAnswerData(mergeList, userListAnswer);
      const xlsxBuilder = new Xlsx(answerExcelHeader);
      const fileName = `${uuidv4()}.xlsx`;

      xlsxBuilder.setData(answerData);

      const resolvePath = xlsxBuilder.generateExcelFile(fileName);

      FileUtil.delayClearFile([fileName], 1000 * 60 * 60 * 12);

      return resolvePath;
    });

    return realResolvePath;
  }

  public async delete(mergeUuid: string) {
    // 首先搜索这个 mergeUuid 的 fk_user 有几条
    // 如果只有一条，需要删除 user 表和 answer 表中的数据
    // 如果有多条，只需要删除 answer 表数据

    const { ctx } = this;

    const res = await ctx.model.transaction(async (t) => {
      const foundAnswer = await ctx
        .model
        .MergeUserQuestionnaire
        .findOne({
          where: {
            uuid: mergeUuid
          },
          attributes: ['fk_user', 'id']
        }, { transaction: t });

      if (!foundAnswer) {
        return false;
      }

      const mergeId = foundAnswer?.id ?? '';
      const userId = foundAnswer?.['fk_user'] ?? '';

      const userAnswerCount = await ctx
        .model
        .MergeUserQuestionnaire
        .count({
          where: {
            fk_user: userId
          }
        }, { transaction: t });

      await ctx
        .model
        .Answer
        .destroy({
          where: {
            FKMergeUserQuestionnaire: mergeId
          }
        }, { transaction: t });

      await ctx
        .model
        .MergeUserQuestionnaire
        .destroy({
          where: {
            id: mergeId
          }
        }, { transaction: t });

      if (userAnswerCount === 1) {
        // 删除 user
        await ctx
          .model
          .User
          .destroy({
            where: {
              id: userId
            }
          }, { transaction: t });
      }

      return true;
    });

    return res;
  }

  async findAllScoreByMergeUuid(mergeUuid: string) {
    const { ctx } = this;

    const answerList = await ctx
      .model
      .MergeUserQuestionnaire
      .findOne({
        where: { uuid: mergeUuid },
        attributes: [],
        include: [
          {
            model: ctx.model.Answer,
            attributes: [
              ['fk_question', 'fkQuestion'],
              'score'
            ],
          },
        ]
      });

    const scoreList = answerList.dataValues.Answers;
    const scoreListSorted = scoreList.sort(
      (a, b) => a.fkQuestion - b.fkQuestion
    );
    const scores = scoreListSorted.map((list) => list.score);

    return scores;
  }

  public async saveAnswer({
    questionnaireUuid,
    mergeUuid,
    name,
    num,
    tel,
    gender,
    maritalStatus,
    childrenSituation,
    age,
    education,
    score,
    jobPosition,
    affiliated,
    workUnit,
    operatingPost,
    email
  }: SaveAnswerParams) {
    // 需要对多个表进行更新、插入操作
    // 顺序是 user -> merge -> answer
    // user 表 => 创建/更新
    // merge 表 => 创建
    // answer 表 => 删除 -> 创建多个
    const { ctx } = this;

    let where: { uuid: string } | null = null;

    if (mergeUuid) {
      where = {
        uuid: mergeUuid
      };
    }

    const result = await this.ctx.model.transaction(async (t) => {
      const [merge, questionnaire, foundUser] = await Promise.all([
        ctx.model.MergeUserQuestionnaire.findOne({
          where,
          attributes: ['id'],
          transaction: t
        }),
        ctx.model.Questionnaire.findOne({
          where: {
            uuid: questionnaireUuid
          },
          attributes: ['id'],
          transaction: t
        }),
        ctx.model.User.findOne({
          include: [{
            model: ctx.model.MergeUserQuestionnaire,
            required: true,
            where
          }],
          transaction: t
        })
      ]);

      if (mergeUuid && merge && questionnaire && foundUser) {
        // 更新
        foundUser.name = name;
        foundUser.num = num;
        foundUser.gender = gender;
        foundUser.maritalStatus = maritalStatus;
        foundUser.childrenSituation = childrenSituation;
        foundUser.age = age;
        foundUser.education = education;
        foundUser.jobPosition = jobPosition;
        foundUser.affiliated = affiliated;
        foundUser.workUnit = workUnit;
        foundUser.operatingPost = operatingPost;
        merge.email = email;

        await foundUser.save({
          transaction: t
        });

        await merge.save({
          transaction: t
        });

        await ctx
          .model
          .Answer
          .destroy({
            include: [{
              model: ctx.model.MergeUserQuestionnaire,
              attributes: [],
            }],
            where: {
              FKMergeUserQuestionnaire: merge.id,
            },
            transaction: t
          });

        const bulkCreateParams = score.map((scoreItem, index) => ({
          uuid: uuidv4(),
          FKMergeUserQuestionnaire: merge.id,
          FKQuestion: index + 1,
          score: scoreItem
        }));

        await ctx
          .model
          .Answer
          .bulkCreate(
            bulkCreateParams,
            { transaction: t }
          );

        return true;
      }

      // 创建
      await ctx.model.User.destroy({
        where: {
          tel
        },
        transaction: t
      });

      const createdUser = await ctx.model.User.create({
        name,
        num,
        tel,
        gender,
        maritalStatus,
        childrenSituation,
        age,
        education,
        jobPosition,
        affiliated,
        workUnit,
        operatingPost,
        uuid: uuidv4(),
        complateFlag: 1
      }, {
        transaction: t
      });

      const createdMerge = await ctx.model.MergeUserQuestionnaire.create({
        uuid: uuidv4(),
        FKUser: createdUser.id,
        FKQuestionnaire: questionnaire.id,
        complateFlag: 1,
        email
      }, { transaction: t });

      const bulkCreateParams = score.map((scoreItem, index) => ({
        uuid: uuidv4(),
        FKMergeUserQuestionnaire: createdMerge.id,
        FKQuestion: index + 1,
        score: scoreItem
      }));

      await ctx
        .model
        .Answer
        .bulkCreate(
          bulkCreateParams,
          { transaction: t }
        );

      return true;
    });

    return result;
  }
}

export default AnswerService;
